package com.execjar;

import cn.hutool.core.util.StrUtil;
import com.execjar.fun.FunctionCalc;
import com.execjar.fun.FunctionParse;
import com.execjar.fun.FunctionPound;
import com.execjar.fun.FunctionSleep;
import com.execjar.utils.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhuzi
 * 2024/12/18 22:6
 */
@Slf4j
public class ReadPounda {

    static FunctionParse<List<byte[]>, Integer> funParse = (listByte) -> Optional.ofNullable(listByte).map(item -> Integer.parseInt(listByteToInt(item))).get();

    static FunctionPound<String, String, Integer, List<byte[]>> funcPoundList = (ip, port, readLen) -> TcpToolUtils.postReAssignByteList(ip, Integer.parseInt(port), readLen, 500);

    static String listByteToInt(List<byte[]> list) {
        List<String> collect = list.stream().map(ia -> new String(ia, StandardCharsets.UTF_8).trim()).filter(ib -> StringUtils.isNotBlank(ib) && ib.trim().length() >= 9).map(id -> {
            log.info("地磅3a解析01-[{}]", id);
            List<String> split1 = StrUtil.splitTrim(id, "+");
            return split1.stream().filter(ic -> StringUtils.isNotBlank(ic) && ic.trim().length() >= 9).map(ie -> {
                ie = ie.trim();
                return StringUtils.substring(ie, 1, ie.length() - 3);
            }).collect(Collectors.toList());
        }).flatMap(List::stream).collect(Collectors.toList());
        log.info("地磅3a解析集合[{}]", collect);
        return collect.get(collect.size() / 2);
    }

    /**
     * 睡眠间隔|1秒是根据实际情况测试出来的
     */
    static FunctionSleep funSleep = () -> SleepUtils.sleep(1, TimeUnit.SECONDS);


    public static void main12(String[] args) {
        EquDTO equDTO = new EquDTO();
        equDTO.setEqpIp(args[0]);
        equDTO.setEqpPort(args[1]);
        int loopNum = 10;
        loopReadList(equDTO, loopNum, 5, 4, 4, 50, funcPoundList, funParse, funSleep, CalculUtils::mode);

        log.info("结果[{}]", equDTO.getResult());
    }

    public static void loopReadList(EquDTO equDTO, int loopNum, int validNumber, int netErrNum, int parseErrNum, int readLength, FunctionPound<String, String, Integer, List<byte[]>> funcPound, FunctionParse<List<byte[]>, Integer> funParseRead, FunctionSleep funSleep, FunctionCalc<List<Integer>, Integer> funCalc) {

        // 记录错误次数
        int tmpnetErrNum = 0;
        int tmpparseErrNum = 0;
        String pound = "";
        List<Integer> wList = new ArrayList<>();
        Boolean netErr = Boolean.TRUE;
        for (int i = 1; i <= loopNum; i++) {
            try {
                List<byte[]> tcpRead = funcPound.apply(equDTO.getEqpIp(), equDTO.getEqpPort(), readLength);
                Integer readPound = funParseRead.apply(tcpRead);
                log.info("[{}]读取次数[{}]解析结果[{}]", equDTO.getEqpIp(), i, readPound);
                pound = String.valueOf(readPound);
                wList.add(readPound);
                // 这里也可以提取出去
                if (wList.size() == validNumber) {
                    break;
                }
            } catch (SqException e) {
                if (StringUtils.equals(ConstantEnum.EQU_NET_ERR.getCode(), e.getCode().toString())) {
                    log.error("读取地磅-网络异常-第[{}]次", i, e);
                    tmpnetErrNum++;
                } else {
                    netErr = Boolean.FALSE;
                    log.error("读取地磅-解析地磅错误-第[{}]次", i, e);
                    tmpparseErrNum++;
                }
            } catch (IOException e) {
                log.error("读取地磅-网络异常-第[{}]次", i, e);
                tmpnetErrNum++;
            } catch (Exception e) {
                log.error("读取地磅-解析地磅错误-第[{}]次", i, e);
                tmpparseErrNum++;
            }
            if (tmpnetErrNum > netErrNum) {
                throw new SqException(Integer.valueOf(ConstantEnum.EQU_NET_ERR.getCode()), ConstantEnum.EQU_NET_ERR.getName());
            }
            if (tmpparseErrNum > parseErrNum) {
                throw new SqException(Integer.valueOf(ConstantEnum.EQU_MSG_ERR.getCode()), ConstantEnum.EQU_MSG_ERR.getName());
            }
            // 1秒是根据实际情况测试出来的
            funSleep.sleep();
        }
        if (loopNum == 1) {
            //只读一次 读取不到,是网络异常了
            if (StringUtils.isBlank(pound)) {
                if (netErr) {
                    throw new SqException(Integer.valueOf(ConstantEnum.EQU_NET_ERR.getCode()), ConstantEnum.EQU_NET_ERR.getName());
                } else {
                    throw new SqException(Integer.valueOf(ConstantEnum.EQU_MSG_ERR.getCode()), ConstantEnum.EQU_MSG_ERR.getName());
                }

            }
            log.info("单次读取[{}]计算完成[{}]", equDTO.getEqpIp(), pound);
            equDTO.setResult(pound);
        } else {
            Integer max = funCalc.apply(wList);
            log.info("[{}]计算完成[{}]", equDTO.getEqpIp(), max);
            equDTO.setResult(String.valueOf(max));
        }
    }

    public static List<byte[]> postReAssignByteList(String ip, int port, int length, int timeOut) {
        Socket socket = null;
        InputStream is = null;
        // 读取成功
        Boolean netErr = Boolean.TRUE;
        ArrayList<byte[]> list = Lists.newArrayList();
        try {
            socket = new Socket();
            //连接超时网络异常
            socket.connect(new InetSocketAddress(ip, port), timeOut);
            socket.setSoTimeout(timeOut);
            netErr = Boolean.FALSE;

            byte[] buffer = new byte[length]; // 可以根据需要调整缓冲区大小
            int bytesRead;
            // 循环读取数据直到连接关闭或发生异常
            for (int count = 0; count < 5; count++) {
                bytesRead = is.read(buffer);
                // 处理接收到的数据
                byte[] message = Arrays.copyOf(buffer, bytesRead);
                log.info("读取到的数据[{}]", new String(message, StandardCharsets.UTF_8));
                list.add(message);
            }
        } catch (Exception e) {
            log.error("TCP错误", e);
            if (netErr) {
                throw new SqException(Integer.valueOf(ConstantEnum.EQU_NET_ERR.getCode()), ConstantEnum.EQU_NET_ERR.getName());
            }
            throw new SqException(Integer.valueOf(ConstantEnum.EQU_MSG_ERR.getCode()), ConstantEnum.EQU_MSG_ERR.getName());
        } finally {
            // 关闭连接和I/O,释放资源
            closeAll(is, socket);
        }
        return list;
    }

    public static void closeAll(Closeable... cs) {
        for (Closeable c : cs) {
            if (c != null) {
                try {
                    c.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        }
    }

}
